﻿using System;
using System.Linq;
using Xenta.Entities;
using Xenta.Structs;
using Xenta.Utils;

namespace Xenta.Operations
{
    #region __General__

    /// <summary>
    /// Creates a comment.
    /// </summary>
    /// <typeparam name="TComment">The type of comment.</typeparam>
    public class CreateComment<TComment> : CreateAuditable<TComment>
        where TComment : CommentEntity
    {
        #region Properties

        /// <summary>
        /// Gets or sets the account identifier.
        /// </summary>
        public int HolderID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the account identifier.
        /// </summary>
        public int AccountID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the title.
        /// </summary>
        public string Title
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the text.
        /// </summary>
        public string Text
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override Err Validate(IUnitOfWork uow)
        {
            if(String.IsNullOrWhiteSpace(Text))
                return Err.Of<CommentEntity>().NotValid("Text");
            return base.Validate(uow);
        }

        protected override void Construct(IUnitOfWork uow, TComment entity)
        {
            base.Construct(uow, entity);

            entity.HolderID = HolderID;
            entity.Account = AccountID != 0 
                ? uow.Execute(new GetAccount
                {
                    ThrowsException = true,
                    EntityID = AccountID
                }).Result
                : null;
            entity.Title = StringHelper.EnsureNotNull(Title).TrimToLen(1000);
            entity.Text = StringHelper.EnsureNotNull(Text).TrimToLen(4000);
        }

        #endregion
    }

    /// <summary>
    /// Updates the comment.
    /// </summary>
    /// <typeparam name="TComment">The type of comment.</typeparam>
    public class UpdateComment<TComment> : UpdateAuditable<TComment>
        where TComment : CommentEntity
    {
        #region Properties

        /// <summary>
        /// Gets or sets the title.
        /// </summary>
        public string Title
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the text.
        /// </summary>
        public string Text
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override Err Validate(IUnitOfWork uow)
        {
            if(String.IsNullOrWhiteSpace(Text))
                return Err.Of<CommentEntity>().NotValid("Text");
            return base.Validate(uow);
        }

        protected override void Revise(IUnitOfWork uow, TComment entity)
        {
            base.Revise(uow, entity);

            entity.Title = StringHelper.EnsureNotNull(Title).TrimToLen(1000);
            entity.Text = StringHelper.EnsureNotNull(Text).TrimToLen(4000);
        }

        #endregion
    }

    /// <summary>
    /// Deletes the comment.
    /// </summary>
    /// <typeparam name="TComment">The type of comment.</typeparam>
    public class DeleteComment<TComment> : DeleteEntity<TComment>
        where TComment : CommentEntity
    {
    }

    /// <summary>
    /// Gets the comment by identifier.
    /// </summary>
    /// <typeparam name="TComment">The type of comment.</typeparam>
    public class GetComment<TComment> : GetEntity<TComment>
        where TComment : CommentEntity
    {
    }

    #endregion

    #region __Search__

    /// <summary>
    /// Search over comment collection.
    /// </summary>
    /// <typeparam name="TComment">The type of comment.</typeparam>
    public class SearchComments<TComment> : SearchOperation<TComment>
        where TComment : CommentEntity
    {
        #region Ctors

        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public SearchComments()
        {
            Term = SearchTerm.Empty;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the search term.
        /// </summary>
        public SearchTerm Term
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the holder identifier.
        /// </summary>
        public int? HolderID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the account identifier.
        /// </summary>
        public int? AccountID
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override IQueryable<TComment> Build(IUnitOfWork uow, IQueryable<TComment> query)
        {
            query = base.Build(uow, query);
            if(HolderID.HasValue)
                query = query.Where(x => x.HolderID == HolderID.Value);
            if(AccountID.HasValue)
                query = query.Where(x => x.Account.EntityID == AccountID.Value);
            switch(Term.Mode)
            {
                case SearchTerm.SearchMode.StartsWith:
                    query = query.Where(x => x.Title.StartsWith(Term.Keyword));
                    break;
                case SearchTerm.SearchMode.EndsWith:
                    query = query.Where(x => x.Text.EndsWith(Term.Keyword));
                    break;
                case SearchTerm.SearchMode.Contains:
                    query = query.Where(x => x.Title.Contains(Term.Keyword) || x.Text.Contains(Term.Keyword));
                    break;
                case SearchTerm.SearchMode.Equals:
                    query = query.Where(x => x.Title.Equals(Term.Keyword));
                    break;
            }
            return query;
        }

        #endregion
    }

    #endregion
}
